/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.sys.modular.coursepublish.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.core.context.login.LoginContextHolder;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.login.SysLoginUser;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.sys.core.enums.AdminTypeEnum;
import vip.xiaonuo.sys.modular.course.entity.Course;
import vip.xiaonuo.sys.modular.course.service.CourseService;
import vip.xiaonuo.sys.modular.coursepublish.entity.CoursePublish;
import vip.xiaonuo.sys.modular.coursepublish.enums.CoursePublishExceptionEnum;
import vip.xiaonuo.sys.modular.coursepublish.mapper.CoursePublishMapper;
import vip.xiaonuo.sys.modular.coursepublish.param.CoursePublishParam;
import vip.xiaonuo.sys.modular.coursepublish.param.CoursePublishParamForSaving;
import vip.xiaonuo.sys.modular.coursepublish.param.StudentCollectionTemplate;
import vip.xiaonuo.sys.modular.coursepublish.result.CoursePublishResult;
import vip.xiaonuo.sys.modular.coursepublish.service.CoursePublishService;
import vip.xiaonuo.sys.modular.coursepublishfrequency.entity.CoursePublishFrequency;
import vip.xiaonuo.sys.modular.coursepublishfrequency.service.CoursePublishFrequencyService;
import vip.xiaonuo.sys.modular.coursepublishstudent.entity.CoursePublishStudent;
import vip.xiaonuo.sys.modular.coursepublishstudent.service.CoursePublishStudentService;
import vip.xiaonuo.sys.modular.courseschedule.entity.CourseSchedule;
import vip.xiaonuo.sys.modular.courseschedule.service.CourseScheduleService;
import vip.xiaonuo.sys.modular.sysschoolterm.entity.SysSchoolTerm;
import vip.xiaonuo.sys.modular.sysschoolterm.service.SysSchoolTermService;
import vip.xiaonuo.sys.modular.sysschoolyear.entity.SysSchoolYear;
import vip.xiaonuo.sys.modular.sysschoolyear.service.SysSchoolYearService;
import vip.xiaonuo.sys.modular.user.param.SysUserParam;
import vip.xiaonuo.sys.modular.user.result.CustomUserResult;
import vip.xiaonuo.sys.modular.user.service.SysUserService;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 开课service接口实现类
 *
 * @author kongxm
 * @date 2022-07-07 21:52:25
 */
@Service
public class CoursePublishServiceImpl extends ServiceImpl<CoursePublishMapper, CoursePublish> implements CoursePublishService {
    private static final Log log = Log.get();
    @Autowired
    private CoursePublishService coursePublishService;
    @Autowired
    private CoursePublishFrequencyService coursePublishFrequencyService;
    @Autowired
    private CoursePublishStudentService coursePublishStudentService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private SysSchoolYearService schoolYearService;
    @Autowired
    private SysSchoolTermService schoolTermService;
    @Autowired
    private CourseScheduleService courseScheduleService;
    @Autowired
    private SysUserService sysUserService;

    @Override
    public PageResult<CoursePublish> page(CoursePublishParam coursePublishParam) {
        QueryWrapper<CoursePublish> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(coursePublishParam)) {

            // 根据院系id 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getCollegeId())) {
                queryWrapper.lambda().eq(CoursePublish::getCollegeId, coursePublishParam.getCollegeId());
            }
            // 根据课程id 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getCourseId())) {
                queryWrapper.lambda().eq(CoursePublish::getCourseId, coursePublishParam.getCourseId());
            }
            // 根据学年id 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getSchoolYearId())) {
                queryWrapper.lambda().eq(CoursePublish::getSchoolYearId, coursePublishParam.getSchoolYearId());
            }
            // 根据学期id 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getTermId())) {
                queryWrapper.lambda().eq(CoursePublish::getTermId, coursePublishParam.getTermId());
            }
            // 根据备注说明 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getRemark())) {
                queryWrapper.lambda().eq(CoursePublish::getRemark, coursePublishParam.getRemark());
            }
            // 根据选课开始时间 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getSelectionStartDate())) {
                queryWrapper.lambda().eq(CoursePublish::getSelectionStartDate, coursePublishParam.getSelectionStartDate());
            }
            // 根据选课结束时间 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getSelectionEndDate())) {
                queryWrapper.lambda().eq(CoursePublish::getSelectionEndDate, coursePublishParam.getSelectionEndDate());
            }
            // 根据0-待发布 1-已发布 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getPublishState())) {
                queryWrapper.lambda().eq(CoursePublish::getPublishState, coursePublishParam.getPublishState());
            }
            // 根据状态（字典 0正常 1冻结 2删除） 查询
            if (ObjectUtil.isNotEmpty(coursePublishParam.getStatus())) {
                queryWrapper.lambda().eq(CoursePublish::getStatus, coursePublishParam.getStatus());
            }
        }
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public PageResult<CoursePublishResult> pageWithName(CoursePublishParam coursePublishParam) {
        if (LoginContextHolder.me().isSuperAdmin()) { //系统管理员：查看所有数据
            // don't filter data
            log.debug("系统管理员：查看所有数据");
        } else if (LoginContextHolder.me().hasRole("ca")) {
            //院系管理员：查看本院系的数据
            Long collegeId = LoginContextHolder.me().getSysLoginUser().getCollId();
            coursePublishParam.setCollegeId(collegeId);
        } else {//教师：没有本页面的查看权限。
            return new PageResult<>();
        }
        Page<CoursePublishResult> page = this.baseMapper.pageWithName(PageFactory.defaultPage(), coursePublishParam);
        //处理选课状态
        page.getRecords().forEach(item -> {
            //无：当用户没有维护选课日期，则“选课状态”为“无”。
            if (item.getSelectionStartDate() == null || item.getSelectionEndDate() == null) {
                item.setSelectionState("无");
                return;
            }
            // 1-当“开课状态”为“已发布”
            if (item.getPublishState() == 1) {
                //1.1-未开始：选课开始日期大于当前日期，则显示“未开始”。
                Date now = new Date();
                if (item.getSelectionStartDate().compareTo(now) > 0) {
                    item.setSelectionState("未开始");
                    return;
                }
                //1.2-选课中：选课开始日期小于当前日期，并且选课结束日期大于当前日期，则显示“选课中”。
                if (item.getSelectionStartDate().compareTo(now) <= 0 && item.getSelectionEndDate().compareTo(now) >= 0) {
                    item.setSelectionState("选课中");
                    return;
                }
                //1.3-选课确认中：选课结束日期小于当前日期，并且老师没有点击“确认选课”，则显示“选课确认中”。
                if (item.getSelectionEndDate().compareTo(now) < 0 && item.getConfirmState() != 4) {
                    item.setSelectionState("选课确认中");
                    return;
                }
                //1.4-已确认：并且老师点击“确认选课”，则显示“已确认”。
                if (item.getConfirmState() == 4) {
                    item.setSelectionState("已确认");
                    return;
                }
            }

            //当“开课状态”是“待发布”时，不显示“选课状态”。
            if (item.getPublishState() == 0) {
                item.setSelectionState("");
                return;
            }
            //将“开课状态”从“已发布”调整为“待发布”，如果“选课状态”是“已确认”，则仍然显示为“已确认”；
            if (item.getPublishState() == 0 && item.getConfirmState() == 4) {
                item.setSelectionState("已确认");
            }
            //如果“选课状态”是其他状态，则根据选课的开始结束日期来重新更新选课状态。(bullshit)
            //编辑“开课课程”后，当“选课状态”为“已发布”时，“选课状态”不变；其他情况，需要根据选课的开始结束日期来重新更新选课状态。(what did you say?amusing!)
        });
        return new PageResult<>(page);
    }

    @Override
    public List<CoursePublishResult> list(CoursePublishParam coursePublishParam) {
        SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUser();
        if (sysLoginUser.getAdminType() != 1) {
            coursePublishParam.setCollegeId(sysLoginUser.getCollId());
        }
        return this.baseMapper.list(coursePublishParam);
    }

    @Override
    public void add(CoursePublishParam coursePublishParam) {
        CoursePublish coursePublish = new CoursePublish();
        BeanUtil.copyProperties(coursePublishParam, coursePublish);
        this.save(coursePublish);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(CoursePublishParamForSaving coursePublishParamForSaving) {
        CoursePublish coursePublish = new CoursePublish();
        BeanUtil.copyProperties(coursePublishParamForSaving, coursePublish);
        save(coursePublish);

        // getting the ID of the inserted coursePublish and then assign it to subItems
        coursePublishParamForSaving.getFrequencyList().forEach(item -> {
            item.setCoursePublishId(coursePublish.getId());
            item.setCourseId(coursePublish.getCourseId());
            coursePublishFrequencyService.add(item);
        });

        coursePublishParamForSaving.getStudentList().forEach(item -> {
            item.setCoursePublishId(coursePublish.getId());
            coursePublishStudentService.add(item);
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<CoursePublishParam> coursePublishParamList) {
        coursePublishParamList.forEach(coursePublishParam -> {
            CoursePublish coursePublish = new CoursePublish();
            coursePublish.setId(coursePublishParam.getId());
            coursePublish.setStatus(2);
            this.updateById(coursePublish);
            // delete courseSchedule also
            courseScheduleService.update(new LambdaUpdateWrapper<CourseSchedule>()
                    .eq(CourseSchedule::getCoursePublishId, coursePublishParam.getId())
                    .set(CourseSchedule::getStatus, 2));
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(CoursePublishParam coursePublishParam) {
        CoursePublish coursePublish = this.queryCoursePublish(coursePublishParam);
        BeanUtil.copyProperties(coursePublishParam, coursePublish);
        this.updateById(coursePublish);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(CoursePublishParamForSaving coursePublishParamForSaving) {
        CoursePublish coursePublish = this.queryCoursePublish(coursePublishParamForSaving);
        //当“开课状态”为“已发布”，
        if (coursePublish.getPublishState() == 1) {
            if (coursePublish.getConfirmState() == 4) { //“选课状态”是“已确认”，则不可以编辑开课课程；
                throw new ServiceException(CoursePublishExceptionEnum.NOT_EDITABLE);
            } else { //“选课状态”不是“已确认”，则只可以编辑“选课起止时间”和“开放学生类别”；
                //选课起止时间
                coursePublish.setId(coursePublishParamForSaving.getId());
                if (StringUtils.isNotEmpty(coursePublishParamForSaving.getSelectionStartDate())) {
                    coursePublish.setSelectionStartDate(DateUtil.parse(coursePublishParamForSaving.getSelectionStartDate(), "yyyy-MM-dd HH:mm:ss"));
                } else {
                    coursePublish.setSelectionStartDate(null);
                }
                if (StringUtils.isNotEmpty(coursePublishParamForSaving.getSelectionEndDate())) {
                    coursePublish.setSelectionEndDate(DateUtil.parse(coursePublishParamForSaving.getSelectionEndDate(), "yyyy-MM-dd HH:mm:ss"));
                } else {
                    coursePublish.setSelectionEndDate(null);
                }
                this.updateById(coursePublish);
                //开放学生类别
                saveStudents(coursePublishParamForSaving, coursePublish.getId());
            }
            return;
        }

        // “开课状态”是“待发布”，可以编辑所有内容。
        BeanUtil.copyProperties(coursePublishParamForSaving, coursePublish, "selectionStartDate", "selectionEndDate");
        if (StringUtils.isNotEmpty(coursePublishParamForSaving.getSelectionStartDate())) {
            coursePublish.setSelectionStartDate(DateUtil.parseDateTime(coursePublishParamForSaving.getSelectionStartDate()));
        } else {
            coursePublish.setSelectionStartDate(null);
        }
        if (StringUtils.isNotEmpty(coursePublishParamForSaving.getSelectionEndDate())) {
            coursePublish.setSelectionEndDate(DateUtil.parseDateTime(coursePublishParamForSaving.getSelectionEndDate()));
        } else {
            coursePublish.setSelectionEndDate(null);
        }
        this.updateById(coursePublish);

        //find the ids in the database which doesn't exist in the request params then remove them
        List<CoursePublishFrequency> coursePublishFrequencyListExistInDatabase =
                coursePublishFrequencyService.list(new LambdaQueryWrapper<CoursePublishFrequency>()
                        .eq(CoursePublishFrequency::getCoursePublishId, coursePublishParamForSaving.getId()));

        List<Long> idsByDeleteFrequency = coursePublishFrequencyListExistInDatabase.stream()
                .filter(item -> coursePublishParamForSaving.getFrequencyList()
                        .stream().noneMatch(subItem -> subItem.getId() != null && subItem.getId().equals(item.getId())))
                .map(CoursePublishFrequency::getId).collect(Collectors.toList());
        coursePublishFrequencyService.removeByIds(idsByDeleteFrequency);


        //add the frequency list,when the method is update, the frontend must pass the id to backend otherwise it will be inserted.
        coursePublishParamForSaving.getFrequencyList().forEach(item -> {
            CoursePublishFrequency entity = new CoursePublishFrequency();
            BeanUtil.copyProperties(item, entity);
            entity.setCoursePublishId(coursePublish.getId());
            entity.setCourseId(coursePublish.getCourseId());
            coursePublishFrequencyService.saveOrUpdate(entity);
        });

        saveStudents(coursePublishParamForSaving, coursePublish.getId());
    }

    private void saveStudents(CoursePublishParamForSaving coursePublishParamForSaving, Long coursePublishId) {
        // delete old data first
        coursePublishStudentService.remove(new LambdaUpdateWrapper<CoursePublishStudent>().
                eq(CoursePublishStudent::getCoursePublishId, coursePublishId));

        coursePublishParamForSaving.getStudentList().forEach(item -> {
            item.setCoursePublishId(coursePublishId);
            CoursePublishStudent entity = new CoursePublishStudent();
            BeanUtil.copyProperties(item, entity);
            coursePublishStudentService.saveOrUpdate(entity);
        });
    }

    @Override
    public CoursePublish detail(CoursePublishParam coursePublishParam) {
        return this.queryCoursePublish(coursePublishParam);
    }

    /**
     * 获取开课
     *
     * @author kongxm
     * @date 2022-07-07 21:52:25
     */
    private CoursePublish queryCoursePublish(CoursePublishParam coursePublishParam) {
        CoursePublish coursePublish = this.getById(coursePublishParam.getId());
        if (ObjectUtil.isNull(coursePublish)) {
            throw new ServiceException(CoursePublishExceptionEnum.NOT_EXIST);
        }
        this.getConfirmState(coursePublish);
        return coursePublish;
    }

    /**
     * 计算选课状态
     *
     * @param coursePublish
     */
    private void getConfirmState(CoursePublish coursePublish) {
        Date now = new Date();
        if (null != coursePublish) {
            //计算选了状态
            if (coursePublish.getConfirmState() != 4) {
                if (coursePublish.getSelectionStartDate() == null || coursePublish.getSelectionEndDate() == null) {
                    //当用户没有维护选课日期，则“选课状态”为“无”。
                    coursePublish.setConfirmState(0);
                } else {
                    if (coursePublish.getPublishState() == 1) {
                        //当“开课状态”为“已发布”，选课开始日期大于当前日期，则显示“未开始”。
                        if (DateUtil.between(now, coursePublish.getSelectionStartDate(), DateUnit.SECOND, false) > 0) {
                            coursePublish.setConfirmState(1);
                        }
                        //当“开课状态”为“已发布”，选课开始日期小于当前日期，并且选课结束日期大于当前日期，则显示“选课中”。
                        if (DateUtil.between(coursePublish.getSelectionStartDate(), now, DateUnit.SECOND, false) >= 0 && DateUtil.between(now, coursePublish.getSelectionEndDate(), DateUnit.SECOND, false) >= 0) {
                            coursePublish.setConfirmState(2);
                        }
                        //当“开课状态”为“已发布”，选课结束日期小于当前日期，并且老师没有点击“确认选课”，则显示“选课确认中”。
                        if (DateUtil.between(coursePublish.getSelectionEndDate(), now, DateUnit.SECOND, false) > 0) {
                            coursePublish.setConfirmState(3);
                        }
                    }
                }
            }
        }
    }


    @Override
    public void export(CoursePublishParam coursePublishParam) {
        List<CoursePublishResult> list = this.list(coursePublishParam);
        PoiUtil.exportExcelWithStream("SnowyCoursePublish.xls", CoursePublish.class, list);
    }

    @Override
    public void publish(Long id) {
        //judgement if the record is exist
        CoursePublish persistence = getById(id);
        if (ObjectUtil.isNull(persistence)) {
            throw new ServiceException(CoursePublishExceptionEnum.NOT_EXIST);
        }
        // only can publish the record that it's publishState is not published
        if (persistence.getPublishState() == 1) {
            throw new ServiceException(CoursePublishExceptionEnum.PUBLISHED);
        }
        // 同一开课课程，同一学期存在已发布的开课记录，则提示用户：2021-2022学年，春季学期，综合化学实验课程已经发布，
        // 同一学期不可以发布同样的课程。模板：【开课学年】，【开课学期】，【开课课程】课程已经发布，同一学期不可以发布同样的课程
        int existRecordCount = count(new LambdaQueryWrapper<CoursePublish>()
                .eq(CoursePublish::getCourseId, persistence.getCourseId())
                .eq(CoursePublish::getSchoolYearId, persistence.getSchoolYearId())
                .eq(CoursePublish::getTermId, persistence.getTermId())
                .eq(CoursePublish::getPublishState, 1));
        if (existRecordCount > 0) {
            SysSchoolYear schoolYear = schoolYearService.getById(persistence.getSchoolYearId());
            SysSchoolTerm schoolTerm = schoolTermService.getById(persistence.getTermId());
            Course course = courseService.getById(persistence.getCourseId());
            throw new ServiceException(-1, String.format("【%s】 【%s】 【%s】 课程已经发布，同一学期不可以发布同样的课程",
                    schoolYear.getName(), schoolTerm.getName(), course.getName()));
        }

        CoursePublish coursePublish = new CoursePublish();
        coursePublish.setId(id);
        coursePublish.setPublishState(1);
        //这里一定要设置，否则会丢失值
        coursePublish.setSelectionStartDate(persistence.getSelectionStartDate());
        coursePublish.setSelectionEndDate(persistence.getSelectionEndDate());
        updateById(coursePublish);
    }

    @Override
    public void rollback(Long id) {
//        3, 当开课状态是“已发布”时，显示按钮“撤回”，点击“撤回”按钮，修改开课课程的状态为“待发布”。
        //judgement if the record is exist
        CoursePublish persistence = getById(id);
        if (ObjectUtil.isNull(persistence)) {
            throw new ServiceException(CoursePublishExceptionEnum.NOT_EXIST);
        }
        // only can rollback the record that it's publishState is published
        if (persistence.getPublishState() == 0) {
            throw new ServiceException(CoursePublishExceptionEnum.NOT_PUBLISHED);
        }

        CoursePublish coursePublish = new CoursePublish();
        coursePublish.setId(id);
        //这里一定要设置，否则会丢失值
        coursePublish.setSelectionStartDate(persistence.getSelectionStartDate());
        coursePublish.setSelectionEndDate(persistence.getSelectionEndDate());
        coursePublish.setPublishState(0);
        updateById(coursePublish);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copy(Long id) {
        // 点击“复制课程”后，弹框提示用户：您是否确认需要复制当前的开课课程。用户确认后，创建一条状态为“待发布”的内容同当前课程的开课课程，
        // 以及创建本课程下的所有的实验项目，实验项目的状态为“待发布”。同时刷新本页面，让用户可以立即查看到复制的新的开课课程。

        //judgement if the record is exist
        CoursePublish persistence = getById(id);
        if (ObjectUtil.isNull(persistence)) {
            throw new ServiceException(CoursePublishExceptionEnum.NOT_EXIST);
        }
        //“开课课程”复制的属性：学院，开课课程，开课学年，开课学期。
        CoursePublish newCoursePublish = new CoursePublish();
        newCoursePublish.setCollegeId(persistence.getCollegeId());
        newCoursePublish.setCourseId(persistence.getCourseId());
        newCoursePublish.setSchoolYearId(persistence.getSchoolYearId());
        newCoursePublish.setTermId(persistence.getTermId());
        newCoursePublish.setStatus(0);
        newCoursePublish.setPublishState(0);
        this.baseMapper.insert(newCoursePublish);

        //“实验项目排课”复制的属性：学院，开课课程，开课学年，开课学期，实验模块，实验项目。
        List<CourseSchedule> newCourseScheduleList = courseScheduleService
                .list(new LambdaQueryWrapper<CourseSchedule>()
                        .eq(CourseSchedule::getStatus, 0)//copy valid data only.
                        .eq(CourseSchedule::getCoursePublishId, id))
                .stream().map(schedule -> {
                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setCoursePublishId(newCoursePublish.getId());
                    courseSchedule.setCourseId(newCoursePublish.getCourseId());
                    courseSchedule.setModuleId(schedule.getModuleId());
                    courseSchedule.setProjectId(schedule.getProjectId());
                    courseSchedule.setStatus(0);
                    courseSchedule.setState(0);
                    return courseSchedule;
                }).collect(Collectors.toList());
        courseScheduleService.saveBatch(newCourseScheduleList);
    }

    @Override
    public void exportStudentCollectionTemplate() {
        PoiUtil.exportExcelWithStream("学生采集模板.xls", StudentCollectionTemplate.class, ListUtil.empty());
    }

    @Override
    public List<Long> uploadStudentList(Long collegeId, MultipartFile file) {
        // check data
        List<StudentCollectionTemplate> importStudentList = PoiUtil.importExcel(file, 0, 1, StudentCollectionTemplate.class);

        if (CollectionUtils.isEmpty(importStudentList))
            throw new ServiceException(CoursePublishExceptionEnum.IMPORT_STUDENT_LIST_CAN_NOT_EMPTY);

        importStudentList = importStudentList.stream().filter(stu ->
                StringUtils.isNotEmpty(stu.getStudentNo())
                        && StringUtils.isNotEmpty(stu.getStudentName()))
                .peek(stu -> {
                    stu.setStudentNo(StringUtils.trim(stu.getStudentNo()));
                    stu.setStudentName(StringUtils.trim(stu.getStudentName()));
                }).collect(Collectors.toList());

        List<StudentCollectionTemplate> notMatchedList = new ArrayList<>(2);

        SysUserParam userParam = new SysUserParam();
        userParam.setCollId(collegeId);
        userParam.setUserType(AdminTypeEnum.STUDENT.getLabel());
        List<CustomUserResult> collegeStudentList = sysUserService.listByUserType(userParam).stream()
                .peek(stu -> {
                    stu.setUserNum(StringUtils.trim(stu.getUserNum()));
                    stu.setName(StringUtils.trim(stu.getName()));
                }).collect(Collectors.toList());

        importStudentList.forEach(importStudent -> {
            boolean notExist = collegeStudentList.stream().noneMatch(collegeStudent ->
                    collegeStudent.getUserNum().equals(importStudent.getStudentNo())
                            && collegeStudent.getName().equals(importStudent.getStudentName()));
            if (notExist) notMatchedList.add(importStudent);
        });

        if (CollectionUtils.isNotEmpty(notMatchedList)) {
            String errMsg = notMatchedList.stream().map(item -> String.format("学号:%s,姓名:%s", item.getStudentNo(),
                    item.getStudentName())).collect(Collectors.joining(";")) + "不能与所选学院匹配，请检查导入的数据。";
            throw new ServiceException(CoursePublishExceptionEnum.IMPORT_STUDENT_LIST_NOT_MATCH.getCode(), errMsg);
        }

        List<Long> importedStudentIds = new ArrayList<>(20);
        importStudentList.forEach(importStudent -> {
            collegeStudentList.stream().filter(collegeStudent ->
                    collegeStudent.getUserNum().equals(importStudent.getStudentNo())
                            && collegeStudent.getName().equals(importStudent.getStudentName()))
                    .findAny().ifPresent(collegeStudent -> importedStudentIds.add(collegeStudent.getId()));
        });
        return importedStudentIds;
    }

    @Override
    public int toConfirm(Long id) {
        CoursePublish coursePublish = this.getById(id);
        if (ObjectUtil.isNull(coursePublish)) {
            throw new ServiceException(CoursePublishExceptionEnum.NOT_EXIST);
        }
        this.getConfirmState(coursePublish);
        if (coursePublish.getConfirmState() == 3) {
            CoursePublish entity = new CoursePublish();
            entity.setId(id);
            entity.setConfirmState(4);
            entity.setConfirmTime(new Date());
            //这2个时间给塞回去
            entity.setSelectionStartDate(coursePublish.getSelectionStartDate());
            entity.setSelectionEndDate(coursePublish.getSelectionEndDate());
            return this.baseMapper.updateById(entity);
        } else {
            throw new ServiceException(CoursePublishExceptionEnum.CANNOT_TO_CONFIRM);
        }
    }

    @Override
    public int cancelConfirm(Long id) {
        CoursePublish coursePublish = this.getById(id);
        if (ObjectUtil.isNull(coursePublish)) {
            throw new ServiceException(CoursePublishExceptionEnum.NOT_EXIST);
        }
        if (coursePublish.getConfirmState() == 4) {
            //先清空 然后拿当前的状态
            coursePublish.setConfirmState(0);
            this.getConfirmState(coursePublish);
            CoursePublish entity = new CoursePublish();
            entity.setId(id);
            entity.setConfirmState(coursePublish.getConfirmState());
            //这2个时间给塞回去
            entity.setSelectionStartDate(coursePublish.getSelectionStartDate());
            entity.setSelectionEndDate(coursePublish.getSelectionEndDate());
            return this.baseMapper.updateById(entity);
        } else {
            throw new ServiceException(CoursePublishExceptionEnum.CANNOT_CANCEL_CONFIRM);
        }
    }
}
